package com.yupi.springbootinit.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yupi.springbootinit.autocommit.AutoCommit;
import com.yupi.springbootinit.autocommit.AutoCommitContext;
import com.yupi.springbootinit.autocommit.QuestionEnum;
import com.yupi.springbootinit.common.BaseResponse;
import com.yupi.springbootinit.common.ResultUtils;
import com.yupi.springbootinit.exception.AutoCommitSelfException;
import com.yupi.springbootinit.model.dto.autoCommit.AutoCommitConst;
import com.yupi.springbootinit.model.dto.autoCommit.AutoCommitRequest;
import com.yupi.springbootinit.model.dto.autoCommit.AutoCommitResult;
import com.yupi.springbootinit.model.entity.AutoResult;
import com.yupi.springbootinit.service.AutoCommitService;
import com.yupi.springbootinit.service.AutoResultService;
import com.yupi.springbootinit.service.ClientInfoService;
import com.yupi.springbootinit.utils.svn.SVNUtil;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.rmi.CORBA.Util;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class AutoCommitServiceImpl implements AutoCommitService {

    @Resource
    private SVNUtil svnUtil;

    @Resource
    private AutoCommit autoCommit;
    @Resource
    private ClientInfoService clientInfoService;

    @Resource
    private AutoResultService autoResultService;
    @Override
    public BaseResponse<AutoCommitResult> autoCommit(AutoCommitRequest request) {
        try {
            checkParam(request);
            //通过爬取自用系统客户信息初始化数据
            AutoCommitContext context = clientInfoService.initAutoCommitContext(request);
            //拉代码
            String clientProjectPath = svnUtil.checkout(context.getProjectUrl(),true);
            context.setClientProjectPath(clientProjectPath);
            //判断是否有关联的数据
            StringBuilder message = getMessage(request);
            //获取当前kb所有需要需要覆盖的文件相对路径，不包含sql脚本文件
            List<String> allwithKb = QuestionEnum.getAllFilePathWithKb(context.getKb());
            /**
             * 1.把文件从模板库移动到客户本地仓库
             * 2.如果已经提交的则不会移动
             * 3.所有的移动结果会再rightFileList中
             */
            AutoCommit.FileActionResult fileActionResult = autoCommit.copyAllFile(context.getClientBakFilePath(), clientProjectPath, allwithKb, false, true);
            context.setFileActionResult(fileActionResult);
            //对比文件，是否有差异
            /**
             * 对比文件差异
             * 差异文件会再目标库中直接移除
             * 无差异文件会在rightFileList中返回
             */
            AutoCommit.FileActionResult compareFileList = autoCommit.compareFileList(autoCommit.getInitStencilPath(context, true), clientProjectPath, fileActionResult.getRightFileList(), true);
            //对比结果记录在上下文里
            context.setFileActionResult(compareFileList);
            //将无差异文件写入文件中，这些文件是本次自动化任务最终会提交的文件（不包括脚本文件）
            String clientHasInitFile = autoCommit.writeCopyFileList(context,true);
            //初始化提交
            AutoCommit.FileActionResult sqlList = autoCommit.sqlScriptInset(context);
            svnUtil.add(clientProjectPath);
            svnUtil.commit(clientProjectPath, "qc:"+request.getQc()+"   "+AutoCommitConst.COMMIT_MSG+"初始化");
            //覆盖模板库代码，这里仅复制已经完成的
            AutoCommit.FileActionResult coverFileList = autoCommit.copyAllFile(autoCommit.getStencilPath(context, true), clientProjectPath, clientHasInitFile, true, false);
            List<String> rightFileList = coverFileList.getRightFileList();
            //二次add 主要是添加sql脚本
            svnUtil.add(clientProjectPath);
            //二次提交，将修改过的文件以及sql脚本同时提交
            svnUtil.commit(clientProjectPath, "qc:"+request.getQc()+"   "+AutoCommitConst.COMMIT_MSG+"提交");
            List<String> checkMsg = new ArrayList<>();
            //后置验证，校验哪些文件冲突
            List<String> hintFile = compareFileList.getLeftFileList();
            List<String> hasCommitFile = fileActionResult.getLeftFileList();
            if (hasCommitFile != null && hasCommitFile.size() > 0) {
                checkMsg.addAll(hasCommitFile);
            }
            if (hintFile != null && hintFile.size() > 0) {
                checkMsg.addAll(hintFile);
            }
            long lastCommitVersionId = svnUtil.getLastCommitVersionId(context.getProjectUrl());
            //组合提交信息
            List<String> rightFile = finMsg(context, rightFileList, sqlList.getRightFileList(), lastCommitVersionId);
            AutoCommitResult autoCommitResult = new AutoCommitResult();
            AutoCommitResult build = autoCommitResult.build(rightFile, hintFile, hasCommitFile,context.getKb(),message.toString());
            String resultMsg = JSONObject.toJSONString(build);
            log.info("result::::{}", resultMsg);
            AutoResult autoResult = insertResultMsg(request, resultMsg, context);
            try {
                autoResultService.save(autoResult);
            } catch (Exception e) {
                log.error("存储异常：",e);
                log.info("未存储信息：",JSONObject.toJSONString(autoResult));
            }
            return ResultUtils.success(build);
        } catch (Exception e) {
            log.error("异常：：：：：",e);
            return ResultUtils.error(-100, e.getMessage());
        }
    }

    @NotNull
    private StringBuilder getMessage(AutoCommitRequest request) {
        QueryWrapper<AutoResult> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("custom_id", request.getCustomerId());
        queryWrapper.orderBy(false,false,"create_time");
        List<AutoResult> autoResults = autoResultService.list(queryWrapper);
        StringBuilder message = new StringBuilder();
        if (!autoResults.isEmpty()) {
            message.append("当前客户可能已经提交过信息<br/>");
            Date createTime = autoResults.get(0).getCreateTime();
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

            message.append("最后一次处理时间:").append(simpleDateFormat.format(createTime)).append("<br/>");
            List<Long> qcs = autoResults.stream().filter(autoResult -> autoResult.getQc() != null && autoResult.getQc() > 0).map(AutoResult::getQc).collect(Collectors.toList());
            Long qc = autoResults.get(0).getQc();
            if (qcs.isEmpty()) {
                message.append("无关联qc");
            } else {
                message.append("关联qc：").append(JSONObject.toJSONString(qcs));
            }
        }
        return message;
    }

    @NotNull
    private static AutoResult insertResultMsg(AutoCommitRequest request, String resultMsg, AutoCommitContext context) {
        AutoResult autoResult = new AutoResult();
        autoResult.setResultMsg(resultMsg);
        autoResult.setKb(context.getKb().toString());
        autoResult.setBakFile(context.getClientBakFilePath());
        autoResult.setCustomName(context.getClientName());
        autoResult.setCustomId(request.getCustomerId());
        autoResult.setCreateTime(new Date());
        autoResult.setQc(request.getQc());
        return autoResult;
    }

    @NotNull
    private static List<String> finMsg(AutoCommitContext context, List<String> rightFileList, List<String> rightSqlList, long lastCommitVersionId) {
        String projectUrl = context.getProjectUrl();
        if (projectUrl.endsWith("/")) {
            projectUrl = projectUrl.substring(0,projectUrl.length()-1);
        }
        rightFileList.addAll(rightSqlList);
        String finalProjectUrl = projectUrl;
        List<String> resultMsgList = rightFileList.stream().map(rawMsg -> {
            //由于sql脚本的特殊性，无法一次性提交，这里需要将sql脚本的版本号改为上次提交的
            long versionTrue = lastCommitVersionId;
            if (rawMsg.endsWith("sql")) {
                versionTrue = lastCommitVersionId-1;

            }
            String replace = rawMsg.replace("\\","/");
            return finalProjectUrl +replace+"(V"+ versionTrue+")";
        }).collect(Collectors.toList());
        return resultMsgList;
    }
    private static void checkParam(AutoCommitRequest request) throws AutoCommitSelfException {
        if (request.getQc() == null) throw new AutoCommitSelfException("qc为空，需要填写qc号");
        if (request.getCustomerId() == null) throw new AutoCommitSelfException("客户id为空，需要填写客户id");
    }
}
